<template>
  <div class="markdown-previewer" :class="currentTheme">
    <div class="outline-panel" :class="{ collapsed: !showOutline }">
      <div class="outline-header">
        <h3>大纲</h3>
        <button @click="toggleOutline" class="close-btn">×</button>
      </div>
      <div class="outline-content">
        <div 
          v-for="(item, index) in outlineItems" 
          :key="index"
          class="outline-item"
          :class="{ active: currentHeading === item.element }"
          :style="{ paddingLeft: item.level * 16 + 'px' }"
          @click="scrollToHeading(item.element)"
        >
          {{ item.text }}
        </div>
      </div>
    </div>
    <div class="main-content">
    <div class="editor-container">
        <div class="editor-preview-wrapper">
      <div class="editor">
            <div class="toolbar">
              <button @click="insertFormat('bold')" title="粗体">B</button>
              <button @click="insertFormat('italic')" title="斜体">I</button>
              <div class="dropdown">
                <button @click="toggleHeadingMenu" title="标题">#</button>
                <div class="dropdown-menu" v-if="showHeadingMenu">
                  <div class="dropdown-item" v-for="i in 6" :key="i" @click="insertHeading(i)">
                    {{'#'.repeat(i)}} 标题 {{i}}
                  </div>
                </div>
              </div>
              <button @click="insertFormat('link')" title="链接">🔗</button>
              <button @click="insertFormat('image')" title="图片">📷</button>
              <div class="dropdown">
                <button @click="toggleListMenu" title="列表">•</button>
                <div class="dropdown-menu" v-if="showListMenu">
                  <div class="dropdown-item" @click="insertList('unordered')">• 无序列表</div>
                  <div class="dropdown-item" @click="insertList('ordered')">1. 有序列表</div>
                  <div class="dropdown-item" @click="insertList('task')">☐ 任务列表</div>
                </div>
              </div>
              <div class="dropdown">
                <button @click="toggleCodeMenu" title="代码">{}</button>
                <div class="dropdown-menu" v-if="showCodeMenu">
                  <div class="dropdown-item" @click="insertCode('inline')">行内代码</div>
                  <div class="dropdown-item" @click="insertCode('block')">代码块</div>
                  <div class="dropdown-divider"></div>
                  <div class="dropdown-item" @click="insertCode('js')">JavaScript</div>
                  <div class="dropdown-item" @click="insertCode('ts')">TypeScript</div>
                  <div class="dropdown-item" @click="insertCode('html')">HTML</div>
                  <div class="dropdown-item" @click="insertCode('css')">CSS</div>
                  <div class="dropdown-item" @click="insertCode('json')">JSON</div>
                  <div class="dropdown-item" @click="insertCode('markdown')">Markdown</div>
                </div>
              </div>
              <button @click="insertFormat('quote')" title="引用">❝</button>
              <button @click="showTableDialog" title="表格">▤</button>
              <div class="template-dropdown">
                <button @click="toggleTemplateMenu" title="模板">📄</button>
                <div class="template-menu" v-if="showTemplates">
                  <div class="template-item" v-for="(template, key) in templates" :key="key" @click="insertTemplate(key)">
                    {{ template.name }}
                  </div>
                </div>
              </div>
              <div class="divider"></div>
              <button @click="toggleOutline" :class="{ active: showOutline }" title="大纲">📑</button>
            </div>
        <textarea 
          v-model="markdownContent" 
          placeholder="在此输入或粘贴 Markdown 内容..."
              @input="handleInput"
              @paste="handlePaste"
              @scroll="handleScroll"
              ref="editorRef"
        ></textarea>
          </div>
          <div class="preview-container">
            <div class="preview-actions">
              <button @click="exportToPDF" class="export-btn" :disabled="isProcessing">
                {{ isProcessing ? '处理中...' : '导出PDF' }}
              </button>
            </div>
            <div class="preview" v-html="htmlContent" ref="previewRef"></div>
          </div>
        </div>
      </div>
      <div class="status-bar">
        <div class="auto-save-status" :class="{ saving: isSaving }">
          {{ saveStatus }}
        </div>
        <div class="theme-selector">
          <button @click="toggleThemeMenu" class="theme-btn">🎨</button>
          <div class="theme-menu" v-if="showThemeMenu">
            <div 
              v-for="theme in themes" 
              :key="theme.name"
              class="theme-item"
              :class="{ active: currentTheme === theme.name }"
              @click="selectTheme(theme.name)"
            >
              {{ theme.label }}
            </div>
          </div>
        </div>
        <div class="ws-status" :class="{ connected: isConnected, error: !isConnected }">
          {{ wsStatus }}
        </div>
      </div>
    </div>
    
    <!-- 表格配置对话框 -->
    <div class="dialog-overlay" v-if="showDialog" @click="closeDialog">
      <div class="dialog" @click.stop>
        <h3>创建表格</h3>
        <div class="dialog-content">
          <div class="input-group">
            <label>行数：</label>
            <input type="number" v-model="tableRows" min="1" max="20">
          </div>
          <div class="input-group">
            <label>列数：</label>
            <input type="number" v-model="tableCols" min="1" max="10">
          </div>
        </div>
        <div class="dialog-actions">
          <button @click="closeDialog">取消</button>
          <button @click="insertTable" class="primary">确定</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, onUnmounted, watch, computed } from 'vue'
import { marked } from 'marked'
import html2pdf from 'html2pdf.js'
import debounce from 'lodash/debounce'
import '../styles/themes.css'
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'

const defaultContent = `# Markdown 使用指南

## 基本语法

### 1. 标题
使用 # 号标记，一级标题使用一个 #，二级标题使用两个 # 号，以此类推：
# 一级标题
## 二级标题
### 三级标题

### 2. 强调
*斜体文本* 或 _斜体文本_
**粗体文本** 或 __粗体文本__
***粗斜体文本*** 或 ___粗斜体文本___

### 3. 列表
无序列表使用 - 或 * 号：
- 项目1
- 项目2
  - 子项目A
  - 子项目B

有序列表使用数字加点：
1. 第一项
2. 第二项
3. 第三项

### 4. 链接和图片
[链接文字](链接地址)
![图片描述](图片地址)

### 5. 引用
> 这是一段引用的文本
> 可以有多行
>> 也可以嵌套引用

### 6. 代码
行内代码：\`console.log('Hello World')\`

代码块：
\`\`\`javascript
function sayHello() {
  console.log('Hello World');
}
\`\`\`

### 7. 表格
| 表头1 | 表头2 |
| ----- | ----- |
| 单元格1 | 单元格2 |
| 单元格3 | 单元格4 |

### 8. 任务列表
- [x] 已完成任务
- [ ] 未完成任务

### 9. 分割线
使用三个或更多的 - 或 * 号：

---

### 10. 数学公式
行内公式：$E = mc^2$

独立公式：
$$
\\sum_{i=1}^n a_i = 0
$$

## 进阶技巧

### 1. 注脚
这里是一个注脚[^1]
[^1]: 这是注脚的内容

### 2. 定义列表
术语
: 定义

### 3. 缩写
*[HTML]: Hyper Text Markup Language

### 4. 标记
==标记的内容==

祝您使用愉快！`

const markdownContent = ref(defaultContent)
const htmlContent = ref('')
const previewRef = ref<HTMLElement | null>(null)
const isProcessing = ref(false)
const editorRef = ref<HTMLTextAreaElement | null>(null)

// 模板数据
const templates = {
  meeting: {
    name: '会议记录',
    content: `# 会议记录

## 基本信息
- 日期：[日期]
- 时间：[时间]
- 地点：[地点]
- 参会人员：[参会人员]

## 会议议程
1. [议程项目1]
2. [议程项目2]
3. [议程项目3]

## 讨论内容
### 1. [主题1]
- 
- 

### 2. [主题2]
- 
- 

## 决议事项
1. 
2. 

## 后续行动
- [ ] [行动项1]
- [ ] [行动项2]

## 下次会议
- 日期：
- 时间：
- 地点：`
  },
  project: {
    name: '项目管理',
    content: `# [项目名称]

## 项目概述
- 项目目标：
- 开始日期：
- 预计完成：
- 项目负责人：
- 项目成员：

## 项目里程碑
1. [ ] 第一阶段 (MM/DD - MM/DD)
   - [ ] 任务1
   - [ ] 任务2
2. [ ] 第二阶段 (MM/DD - MM/DD)
   - [ ] 任务1
   - [ ] 任务2

## 风险管理
| 风险描述 | 可能性 | 影响程度 | 应对策略 |
|---------|--------|----------|----------|
| [风险1]  |        |          |          |
| [风险2]  |        |          |          |

## 资源需求
- 人力资源：
- 技术资源：
- 其他资源：

## 项目进度
- 当前进度：[进度百分比]
- 是否按计划进行：[是/否]
- 存在的问题：
  1. 
  2. 

## 项目文档
- [相关文档1]
- [相关文档2]

## 备注
[其他需要说明的事项]`
  },
  reading: {
    name: '读书笔记',
    content: `# 《[书名]》读书笔记

## 基本信息
- 书名：
- 作者：
- 出版社：
- 阅读时间：
- 阅读进度：[已读页数/总页数]

## 核心内容
### 1. [章节名称]
#### 主要观点
- 
- 

#### 重要概念
1. 
2. 

#### 精彩片段
> [引用原文]

### 2. [章节名称]
#### 主要观点
- 
- 

## 个人感悟
1. 
2. 

## 实践应用
- [ ] [可以应用的想法1]
- [ ] [可以应用的想法2]

## 延伸阅读
- [相关书籍1]
- [相关文章1]

## 总体评价
[对本书的整体评价和推荐指数]`
  },
  weekly: {
    name: '工作周报',
    content: `# 工作周报
## 基本信息
- 姓名：
- 部门：
- 周期：第[X]周 (MM/DD - MM/DD)

## 本周工作内容
### 1. 已完成工作
1. [项目/任务名称]
   - 完成情况：
   - 具体成果：
   - 遇到的问题：
   - 解决方案：

2. [项目/任务名称]
   - 完成情况：
   - 具体成果：
   - 遇到的问题：
   - 解决方案：

### 2. 进行中工作
1. [项目/任务名称]
   - 当前进度：
   - 计划完成时间：
   - 需要协助：

### 3. 工作成果
- [关键指标1]：
- [关键指标2]：

## 下周工作计划
1. [ ] [计划1]
   - 目标：
   - 完成时间：
2. [ ] [计划2]
   - 目标：
   - 完成时间：

## 问题与建议
### 存在的问题
1. 
2. 

### 改进建议
1. 
2. 

## 其他事项
[其他需要说明的内容]`
  },
  daily: {
    name: '工作日报',
    content: `# 工作日报
## 基本信息
- 姓名：
- 部门：
- 日期：YYYY/MM/DD
- 星期[X]

## 今日工作内容
### 1. 已完成工作
- [ ] [任务1]
  - 完成情况：
  - 耗时：
  - 成果：
- [ ] [任务2]
  - 完成情况：
  - 耗时：
  - 成果：

### 2. 进行中工作
- [ ] [任务1]
  - 当前进度：
  - 计划完成时间：
  - 遇到的问题：

### 3. 临时任务
- [ ] [临时任务1]
  - 优先级：
  - 状态：

## 今日工作总结
### 主要成果
1. 
2. 

### 遇到的问题
1. 
2. 

### 解决方案
1. 
2. 

## 明日工作计划
1. [ ] [计划1]
   - 预计耗时：
   - 优先级：
2. [ ] [计划2]
   - 预计耗时：
   - 优先级：

## 需要协助
[需要其他同事或领导协助的事项]

## 备注
[其他需要说明的事项]`
  },
  blog: {
    name: '博客文章',
    content: `# [文章标题]

## 简介
[在这里写文章的简要介绍]

## 目录
1. [第一部分]
2. [第二部分]
3. [第三部分]

## 正文
### [第一部分]
[内容]

### [第二部分]
[内容]

### [第三部分]
[内容]

## 总结
[总结内容]

## 参考资料
- [参考1]
- [参考2]`
  },
  todo: {
    name: '待办清单',
    content: `# 待办事项清单

## 今日任务
- [ ] [重要任务1]
- [ ] [重要任务2]
- [ ] [普通任务1]

## 本周目标
1. [ ] [目标1]
2. [ ] [目标2]
3. [ ] [目标3]

## 进行中
- [ ] [进行中的任务1]
- [ ] [进行中的任务2]

## 已完成
- [x] [已完成的任务1]
- [x] [已完成的任务2]

## 备注
[其他需要记录的事项]`
  }
}

// 表格对话框相关
const showDialog = ref(false)
const tableRows = ref(3)
const tableCols = ref(3)

// 模板菜单相关
const showTemplates = ref(false)

// 大纲相关
const showOutline = ref(true)
const outlineItems = ref<OutlineItem[]>([])

// 主题配置
const themes = [
  { name: 'github', label: 'GitHub' },
  { name: 'monokai', label: 'Monokai' },
  { name: 'solarized', label: 'Solarized' },
  { name: 'dracula', label: 'Dracula' }
]

const currentTheme = ref('github')
const showThemeMenu = ref(false)
const isSaving = ref(false)
const saveStatus = ref('已保存')

// 使用 watch 来处理自动保存
watch(markdownContent, debounce(() => {
  isSaving.value = true
  saveStatus.value = '保存中...'
  
  try {
    localStorage.setItem('markdown-content', markdownContent.value)
    saveStatus.value = '已保存'
  } catch (error) {
    saveStatus.value = '保存失败'
  } finally {
    isSaving.value = false
  }
}, 1000))

// 在 setup 中添加
const ydoc = new Y.Doc()
const ytext = ydoc.getText('markdown')
const wsProvider = new WebsocketProvider(
  'ws://localhost:1234', // WebSocket 服务器地址
  'markdown-room', // 房间名称
  ydoc
)

// 监听远程更改
onMounted(() => {
  // 观察文本变化
  ytext.observe(event => {
    // 更新本地内容
    if (!event.transaction.local) {
      markdownContent.value = ytext.toString()
      updatePreview()
    }
  })

  // 初始化内容
  markdownContent.value = ytext.toString() || defaultContent
  updatePreview()
})

// 修改 handleInput 函数
const handleInput = async () => {
  // 发送更新到其他客户端
  if (isConnected.value && ws.value) {
    ws.value.send(markdownContent.value)
  }
  
  const html = await Promise.resolve(marked(markdownContent.value))
  htmlContent.value = html
  updateOutline()
}

watch(markdownContent, debounce(() => {
  localStorage.setItem('markdown-content', markdownContent.value)
}, 1000))

// 在组件卸载时清理
onUnmounted(() => {
  wsProvider.disconnect()
  ydoc.destroy()
})

// 主题切换
const toggleThemeMenu = () => {
  showThemeMenu.value = !showThemeMenu.value
}

const selectTheme = (theme: string) => {
  currentTheme.value = theme
  showThemeMenu.value = false
  localStorage.setItem('markdown-theme', theme)
}

// 加载保存的主题
onMounted(() => {
  const savedTheme = localStorage.getItem('markdown-theme')
  if (savedTheme) {
    currentTheme.value = savedTheme
  }
})

// 关闭对话框
const closeDialog = () => {
  showDialog.value = false
}

// 显示表格对话框
const showTableDialog = () => {
  showDialog.value = true
}

// 切换模板菜单
const toggleTemplateMenu = () => {
  showTemplates.value = !showTemplates.value
}

// 插入模板
const insertTemplate = (templateKey: keyof typeof templates) => {
  markdownContent.value = templates[templateKey].content
  showTemplates.value = false
  updatePreview()
}

// 生成表格
const insertTable = () => {
  if (!editorRef.value) return

  const rows = Math.min(Math.max(1, tableRows.value), 20)
  const cols = Math.min(Math.max(1, tableCols.value), 10)

  // 生成表头
  let table = '\n|'
  for (let i = 0; i < cols; i++) {
    table += ` 表头${i + 1} |`
  }
  
  // 生成分隔行
  table += '\n|'
  for (let i = 0; i < cols; i++) {
    table += ' ----- |'
  }
  
  // 生成数据行
  for (let i = 0; i < rows - 1; i++) {
    table += '\n|'
    for (let j = 0; j < cols; j++) {
      table += ` 内容${i + 1}-${j + 1} |`
    }
  }
  table += '\n'

  const textarea = editorRef.value
  const start = textarea.selectionStart
  const text = textarea.value
  
  markdownContent.value = text.substring(0, start) + table + text.substring(start)
  updatePreview()
  closeDialog()
}

// 更新预览内容
const updatePreview = async () => {
  const html = await Promise.resolve(marked(markdownContent.value))
  htmlContent.value = html
  nextTick(() => {
    updateOutline()
  })
}

// 初始化预览
onMounted(() => {
  updatePreview()
})

// 导出PDF
const exportToPDF = async () => {
  if (!previewRef.value) return
  
  try {
    isProcessing.value = true
    const element = previewRef.value
    const opt = {
      margin: 1,
      filename: 'markdown-preview.pdf',
      image: { type: 'jpeg', quality: 0.98 },
      html2canvas: { scale: 2 },
      jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
    }

    await html2pdf().set(opt).from(element).save()
  } catch (error) {
    console.error('PDF导出失败:', error)
  } finally {
    isProcessing.value = false
  }
}

// 处理粘贴事件
const handlePaste = async (event: ClipboardEvent) => {
  event.preventDefault() // 阻止默认粘贴行为
  
  const clipboardData = event.clipboardData
  if (!clipboardData) return

  // 处理图片粘贴
  const items = clipboardData.items
  for (const item of items) {
    if (item.type.startsWith('image/')) {
      const file = item.getAsFile()
      if (file) {
        try {
          const base64 = await fileToBase64(file)
          // 在光标位置插入图片 Markdown 语法
          const textarea = event.target as HTMLTextAreaElement
          const cursorPos = textarea.selectionStart
          const textBefore = markdownContent.value.substring(0, cursorPos)
          const textAfter = markdownContent.value.substring(cursorPos)
          markdownContent.value = `${textBefore}![图片](${base64})${textAfter}`
          updatePreview()
          return
        } catch (error) {
          console.error('图片处理失败:', error)
        }
      }
      return
    }
  }

  // 处理文本粘贴
  const text = clipboardData.getData('text')
  if (text) {
    const textarea = event.target as HTMLTextAreaElement
    const cursorPos = textarea.selectionStart
    const textBefore = markdownContent.value.substring(0, cursorPos)
    const textAfter = markdownContent.value.substring(cursorPos)
    markdownContent.value = `${textBefore}${text}${textAfter}`
        updatePreview()
  }
}

// 将文件转换为 base64
const fileToBase64 = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => {
      if (typeof reader.result === 'string') {
        resolve(reader.result)
      } else {
        reject(new Error('Failed to convert file to base64'))
      }
    }
    reader.onerror = () => reject(reader.error)
    reader.readAsDataURL(file)
  })
}

// 插入 Markdown 格式
const insertFormat = (type: string) => {
  if (!editorRef.value) return

  const textarea = editorRef.value
  const start = textarea.selectionStart
  const end = textarea.selectionEnd
  const text = textarea.value
  const selectedText = text.substring(start, end)

  let insertion = ''
  switch (type) {
    case 'bold':
      insertion = `**${selectedText || '粗体文本'}**`
      break
    case 'italic':
      insertion = `*${selectedText || '斜体文本'}*`
      break
    case 'heading':
      insertion = `\n# ${selectedText || '标题'}`
      break
    case 'link':
      insertion = `[${selectedText || '链接文字'}](链接地址)`
      break
    case 'image':
      insertion = `![${selectedText || '图片描述'}](图片地址)`
      break
    case 'list':
      insertion = `\n- ${selectedText || '列表项'}`
      break
    case 'code':
      insertion = selectedText.includes('\n') 
        ? `\n\`\`\`\n${selectedText || '代码块'}\n\`\`\`\n`
        : `\`${selectedText || '行内代码'}\``
      break
    case 'quote':
      insertion = `\n> ${selectedText || '引用文本'}`
      break
    case 'table':
      insertion = `\n| 表头1 | 表头2 |\n| ----- | ----- |\n| 内容1 | 内容2 |`
      break
  }

  markdownContent.value = text.substring(0, start) + insertion + text.substring(end)
  updatePreview()

  // 设置光标位置
  nextTick(() => {
    textarea.focus()
    const newCursorPos = start + insertion.length
    textarea.setSelectionRange(newCursorPos, newCursorPos)
  })
}

const toggleOutline = () => {
  showOutline.value = !showOutline.value
  if (showOutline.value) {
    updateOutline()
  }
}

const updateOutline = () => {
  if (!previewRef.value) return
  
  const headings = previewRef.value.querySelectorAll('h1, h2, h3, h4, h5, h6')
  const items: OutlineItem[] = []
  
  headings.forEach((heading) => {
    const level = parseInt(heading.tagName[1])
    items.push({
      text: heading.textContent || '',
      level,
      element: heading as HTMLElement
    })
  })
  
  outlineItems.value = items
}

const currentHeading = ref<HTMLElement | null>(null)

// 修改 scrollToHeading 函数
const scrollToHeading = (element: HTMLElement) => {
  if (element) {
    const rect = element.getBoundingClientRect()
    const offsetTop = rect.top + window.pageYOffset
    window.scrollTo({
      top: offsetTop,
      behavior: 'smooth'
    })
    currentHeading.value = element
  }
}

// 更新当前活动标题
const updateActiveHeading = (event: Event) => {
  if (!previewRef.value) return
  const scrollTop = (event.target as HTMLElement).scrollTop
  const headings = previewRef.value.querySelectorAll('h1, h2, h3, h4, h5, h6')
  let activeHeading: HTMLElement | null = null

  headings.forEach((heading) => {
    const rect = heading.getBoundingClientRect()
    const elementTop = rect.top + window.pageYOffset
    if (elementTop <= scrollTop + 100) {
      activeHeading = heading as HTMLElement
    }
  })

  if (activeHeading) {
    currentHeading.value = activeHeading
  }
}

// 监听预览区域的滚动事件
onMounted(() => {
  const previewElement = previewRef.value
  if (previewElement) {
    previewElement.addEventListener('scroll', updateActiveHeading)
  }
})

// 下拉菜单状态
const showHeadingMenu = ref(false)
const showListMenu = ref(false)
const showCodeMenu = ref(false)

// 切换下拉菜单
const toggleHeadingMenu = () => {
  showHeadingMenu.value = !showHeadingMenu.value
  showListMenu.value = false
  showCodeMenu.value = false
}

const toggleListMenu = () => {
  showListMenu.value = !showListMenu.value
  showHeadingMenu.value = false
  showCodeMenu.value = false
}

const toggleCodeMenu = () => {
  showCodeMenu.value = !showCodeMenu.value
  showHeadingMenu.value = false
  showListMenu.value = false
}

// 点击其他地方关闭下拉菜单
const closeAllDropdowns = () => {
  showHeadingMenu.value = false
  showListMenu.value = false
  showCodeMenu.value = false
}

// 插入标题
const insertHeading = (level: number) => {
  if (!editorRef.value) return
  
  const textarea = editorRef.value
  const start = textarea.selectionStart
  const end = textarea.selectionEnd
  const text = textarea.value
  const selectedText = text.substring(start, end)
  
  const prefix = '#'.repeat(level) + ' '
  const insertion = `\n${prefix}${selectedText || '标题'}\n`
  
  markdownContent.value = text.substring(0, start) + insertion + text.substring(end)
  updatePreview()
  closeAllDropdowns()
  
  nextTick(() => {
    textarea.focus()
    const newCursorPos = start + insertion.length
    textarea.setSelectionRange(newCursorPos, newCursorPos)
  })
}

// 插入列表
const insertList = (type: 'unordered' | 'ordered' | 'task') => {
  if (!editorRef.value) return
  
  const textarea = editorRef.value
  const start = textarea.selectionStart
  const end = textarea.selectionEnd
  const text = textarea.value
  const selectedText = text.substring(start, end)
  
  let insertion = '\n'
  const lines = selectedText ? selectedText.split('\n') : ['列表项']
  
  lines.forEach((line, index) => {
    switch (type) {
      case 'unordered':
        insertion += `- ${line}\n`
        break
      case 'ordered':
        insertion += `${index + 1}. ${line}\n`
        break
      case 'task':
        insertion += `- [ ] ${line}\n`
        break
    }
  })
  
  markdownContent.value = text.substring(0, start) + insertion + text.substring(end)
  updatePreview()
  closeAllDropdowns()
  
  nextTick(() => {
    textarea.focus()
    const newCursorPos = start + insertion.length
    textarea.setSelectionRange(newCursorPos, newCursorPos)
  })
}

// 插入代码
const insertCode = (type: string) => {
  if (!editorRef.value) return
  
  const textarea = editorRef.value
  const start = textarea.selectionStart
  const end = textarea.selectionEnd
  const text = textarea.value
  const selectedText = text.substring(start, end)
  
  let insertion = ''
  if (type === 'inline') {
    insertion = `\`${selectedText || '代码'}\``
  } else {
    const language = type === 'block' ? '' : type
    insertion = `\n\`\`\`${language}\n${selectedText || '// 在此输入代码'}\n\`\`\`\n`
  }
  
  markdownContent.value = text.substring(0, start) + insertion + text.substring(end)
  updatePreview()
  closeAllDropdowns()
  
  nextTick(() => {
    textarea.focus()
    const newCursorPos = start + insertion.length
    textarea.setSelectionRange(newCursorPos, newCursorPos)
  })
}

// 点击文档其他地方关闭下拉菜单
onMounted(() => {
  document.addEventListener('click', (e) => {
    if (!(e.target as HTMLElement).closest('.dropdown')) {
      closeAllDropdowns()
    }
  })
})

interface OutlineItem {
  text: string;
  level: number;
  element: HTMLElement;
}

const handleScroll = (event: Event) => {
  updateActiveHeading(event)
}

const wsStatus = ref('正在连接...')
const isConnected = ref(false)
const ws = ref<WebSocket | null>(null)

// 创建 WebSocket 连接
const connectWebSocket = () => {
  ws.value = new WebSocket('ws://localhost:1234')

  ws.value.onopen = () => {
    console.log('WebSocket 连接已建立')
    wsStatus.value = '已连接'
    isConnected.value = true
    // 发送初始内容
    if (markdownContent.value) {
      ws.value?.send(markdownContent.value)
    }
  }

  ws.value.onclose = () => {
    console.log('WebSocket 连接已关闭')
    wsStatus.value = '已断开'
    isConnected.value = false
    // 尝试重新连接
    setTimeout(connectWebSocket, 3000)
  }

  ws.value.onerror = (error) => {
    console.error('WebSocket 错误:', error)
    wsStatus.value = '连接错误'
    isConnected.value = false
  }

  ws.value.onmessage = (event) => {
    console.log('收到更新:', event.data)
    // 只有当收到的内容与当前内容不同时才更新
    if (event.data !== markdownContent.value) {
      markdownContent.value = event.data
      updatePreview()
    }
  }
}

// 在组件挂载时连接 WebSocket
onMounted(() => {
  connectWebSocket()
  
  // 加载保存的内容
  const savedContent = localStorage.getItem('markdown-content')
  if (savedContent) {
    markdownContent.value = savedContent
  }
  updatePreview()
})

// 在组件卸载时关闭连接
onUnmounted(() => {
  if (ws.value) {
    ws.value.close()
  }
})

// 添加状态栏显示
const statusBarContent = computed(() => {
  return isConnected.value ? '协同编辑已连接' : '协同编辑未连接'
})
</script>

<style scoped>
.markdown-previewer {
  width: 100%;
  flex: 1;
  display: flex;
  box-sizing: border-box;
  background-color: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  margin-bottom: 20px;
}

.outline-panel {
  width: 250px;
  background: white;
  border-right: 1px solid #eee;
  display: flex;
  flex-direction: column;
  height: 100%;
  flex-shrink: 0;
  transition: width 0.3s ease;
}

.outline-panel.collapsed {
  width: 0;
  overflow: hidden;
  border: none;
}

.editor-container {
  display: flex;
  flex: 1;
  margin: 0;
  box-sizing: border-box;
  overflow: hidden;
  flex-direction: column;
}

.editor-preview-wrapper {
  display: flex;
  gap: 30px;
  flex: 1;
  min-height: 0;
  flex-direction: row;
}

.main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  height: 100%;
}

.editor, .preview-container {
  flex: 1;
  background-color: #fafafa;
  border-radius: 8px;
  border: 1px solid #eee;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0;
  width: calc(50% - 15px);
}

.preview-container {
  background-color: #fff;
}

.preview-actions {
  padding: 12px 20px;
  border-bottom: 1px solid #eee;
  background-color: #fafafa;
  text-align: right;
}

.export-btn {
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.2s ease;
}

.export-btn:hover {
  background-color: #45a049;
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.editor {
  position: relative;
}

.toolbar {
  padding: 8px;
  background-color: #f5f5f5;
  border-bottom: 1px solid #eee;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.toolbar button {
  padding: 6px 12px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  color: #333;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
}

.toolbar button:hover {
  background-color: #f0f0f0;
  border-color: #ccc;
  transform: translateY(-1px);
}

.editor textarea {
  flex: 1;
  padding: 20px;
  border: none;
  resize: none;
  font-family: 'Courier New', Courier, monospace;
  font-size: 14px;
  line-height: 1.6;
  outline: none;
  background-color: #fafafa;
  color: #333;
  overflow-y: auto;
}

.preview {
  flex: 1;
  padding: 20px;
  overflow-y: auto;
  background-color: #fff;
}

:deep(pre) {
  background-color: #f6f8fa;
  padding: 16px;
  border-radius: 6px;
  border: 1px solid #eee;
  overflow-x: auto;
  margin: 16px 0;
  page-break-inside: avoid;
  break-inside: avoid;
  white-space: pre-wrap;
  word-wrap: break-word;
}

:deep(code) {
  font-family: 'Courier New', Courier, monospace;
  font-size: 14px;
  background-color: #f6f8fa;
  padding: 2px 6px;
  border-radius: 3px;
  border: 1px solid #eee;
}

:deep(pre code) {
  padding: 0;
  border: none;
  background-color: transparent;
}

:deep(h1) {
  font-size: 2em;
  margin: 0.67em 0;
  border-bottom: 1px solid #eee;
  padding-bottom: 0.3em;
  color: #2c3e50;
}

:deep(h2) {
  font-size: 1.5em;
  margin: 0.83em 0;
  border-bottom: 1px solid #eee;
  padding-bottom: 0.3em;
  color: #2c3e50;
}

:deep(h3), :deep(h4), :deep(h5), :deep(h6) {
  color: #2c3e50;
  margin: 1em 0;
}

:deep(p) {
  margin: 1em 0;
  line-height: 1.6;
  color: #333;
}

:deep(ul), :deep(ol) {
  padding-left: 2em;
  margin: 1em 0;
  color: #333;
}

:deep(blockquote) {
  margin: 1em 0;
  padding: 0.5em 1em;
  color: #666;
  background-color: #f8f9fa;
  border-left: 4px solid #4CAF50;
  border-radius: 0 4px 4px 0;
}

:deep(table) {
  border-collapse: collapse;
  width: 100%;
  margin: 1em 0;
  background-color: #fff;
}

:deep(th), :deep(td) {
  border: 1px solid #eee;
  padding: 12px;
  text-align: left;
}

:deep(th) {
  background-color: #f6f8fa;
  font-weight: 600;
}

:deep(tr:nth-child(even)) {
  background-color: #f9f9f9;
}

:deep(img) {
  max-width: 100%;
  height: auto;
  margin: 1em 0;
  border-radius: 4px;
  border: 1px solid #eee;
  display: block;
}

:deep(img:hover) {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transform: scale(1.01);
  transition: all 0.3s ease;
}

/* 添加自定义滚动条样式 */
.editor textarea::-webkit-scrollbar,
.preview::-webkit-scrollbar {
  display: none;
}

/* 为 Firefox 添加隐藏滚动条的样式 */
.editor textarea,
.preview {
  scrollbar-width: none;
}

.template-dropdown {
  position: relative;
}

.template-menu {
  position: absolute;
  top: 100%;
  left: 0;
  background: white;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  z-index: 1000;
  min-width: 150px;
}

.template-item {
  padding: 8px 16px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.template-item:hover {
  background-color: #f5f5f5;
}

.dialog-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.dialog {
  background: white;
  padding: 20px;
  border-radius: 8px;
  min-width: 300px;
}

.dialog h3 {
  margin: 0 0 20px 0;
}

.dialog-content {
  margin-bottom: 20px;
}

.input-group {
  margin-bottom: 15px;
  display: flex;
  align-items: center;
}

.input-group label {
  width: 60px;
}

.input-group input {
  width: 80px;
  padding: 4px 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

.dialog-actions button {
  padding: 6px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
}

.dialog-actions button.primary {
  background-color: #4CAF50;
  color: white;
  border: none;
}

.dialog-actions button.primary:hover {
  background-color: #45a049;
}

.divider {
  width: 1px;
  height: 24px;
  background-color: #ddd;
  margin: 0 8px;
}

.toolbar button.active {
  background-color: #4CAF50;
  color: white;
  border-color: #4CAF50;
}

.outline-header {
  padding: 12px 16px;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.outline-header h3 {
  margin: 0;
  font-size: 16px;
  color: #333;
}

.close-btn {
  background: none;
  border: none;
  font-size: 20px;
  color: #666;
  cursor: pointer;
  padding: 0 4px;
}

.close-btn:hover {
  color: #333;
}

.outline-content {
  flex: 1;
  overflow-y: auto;
  padding: 12px 0;
  font-size: 13px;
}

.outline-item {
  padding: 4px 16px;
  cursor: pointer;
  color: #666;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: all 0.2s;
  line-height: 1.4;
}

.outline-item:hover {
  background-color: #f5f5f5;
  color: #333;
}

.outline-item.active {
  color: #4CAF50;
  background-color: #f0f7f0;
}

.status-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  background-color: #f5f5f5;
  border-top: 1px solid #eee;
  font-size: 12px;
  color: #666;
}

.word-count {
  flex: 1;
}

.auto-save-status {
  margin: 0 16px;
}

.auto-save-status.saving {
  color: #4CAF50;
}

.theme-selector {
  position: relative;
}

.theme-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 16px;
  padding: 4px 8px;
}

.theme-menu {
  position: absolute;
  bottom: 100%;
  right: 0;
  background: white;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  z-index: 1000;
}

.theme-item {
  padding: 8px 16px;
  cursor: pointer;
  white-space: nowrap;
}

.theme-item:hover {
  background-color: #f5f5f5;
}

.theme-item.active {
  background-color: #4CAF50;
  color: white;
}

/* 主题样式 */
/* GitHub 主题 - 清爽专业的浅色主题 */
.github {
  background-color: #ffffff;
  color: #24292e;
}

.github .editor,
.github .preview-container {
  background-color: #ffffff;
  border-color: #e1e4e8;
}

.github .editor textarea {
  background-color: #ffffff;
  color: #24292e;
}

.github .preview {
  background-color: #ffffff;
  color: #24292e;
}

.github .toolbar,
.github .status-bar {
  background-color: #f6f8fa;
  border-color: #e1e4e8;
}

.github .toolbar button {
  background-color: #ffffff;
  border-color: #e1e4e8;
  color: #24292e;
}

.github .toolbar button:hover {
  background-color: #f3f4f6;
}

.github .outline-panel {
  background-color: #f6f8fa;
  border-color: #e1e4e8;
}

.github .outline-item {
  color: #24292e;
}

.github .outline-item:hover {
  background-color: #f3f4f6;
}

.github .outline-item.active {
  background-color: #0366d6;
  color: #ffffff;
}

/* Monokai 主题 - 经典的深色主题 */
.monokai {
  background-color: #272822;
  color: #f8f8f2;
}

.monokai .editor,
.monokai .preview-container {
  background-color: #272822;
  border-color: #3e3d32;
}

.monokai .editor textarea {
  background-color: #272822;
  color: #f8f8f2;
}

.monokai .preview {
  background-color: #272822;
  color: #f8f8f2;
}

.monokai .toolbar,
.monokai .status-bar {
  background-color: #1e1f1c;
  border-color: #3e3d32;
}

.monokai .toolbar button {
  background-color: #272822;
  border-color: #3e3d32;
  color: #f8f8f2;
}

.monokai .toolbar button:hover {
  background-color: #3e3d32;
}

.monokai .outline-panel {
  background-color: #1e1f1c;
  border-color: #3e3d32;
}

.monokai .outline-item {
  color: #f8f8f2;
}

.monokai .outline-item:hover {
  background-color: #3e3d32;
}

.monokai .outline-item.active {
  background-color: #a6e22e;
  color: #272822;
}

/* Solarized 主题 - 护眼配色 */
.solarized {
  background-color: #fdf6e3;
  color: #657b83;
}

.solarized .editor,
.solarized .preview-container {
  background-color: #fdf6e3;
  border-color: #eee8d5;
}

.solarized .editor textarea {
  background-color: #fdf6e3;
  color: #657b83;
}

.solarized .preview {
  background-color: #fdf6e3;
  color: #657b83;
}

.solarized .toolbar,
.solarized .status-bar {
  background-color: #eee8d5;
  border-color: #ddd6c1;
}

.solarized .toolbar button {
  background-color: #fdf6e3;
  border-color: #eee8d5;
  color: #657b83;
}

.solarized .toolbar button:hover {
  background-color: #eee8d5;
}

.solarized .outline-panel {
  background-color: #eee8d5;
  border-color: #ddd6c1;
}

.solarized .outline-item {
  color: #657b83;
}

.solarized .outline-item:hover {
  background-color: #fdf6e3;
}

.solarized .outline-item.active {
  background-color: #268bd2;
  color: #fdf6e3;
}

/* Dracula 主题 - 现代深色主题 */
.dracula {
  background-color: #282a36;
  color: #f8f8f2;
}

.dracula .editor,
.dracula .preview-container {
  background-color: #282a36;
  border-color: #44475a;
}

.dracula .editor textarea {
  background-color: #282a36;
  color: #f8f8f2;
}

.dracula .preview {
  background-color: #282a36;
  color: #f8f8f2;
}

.dracula .toolbar,
.dracula .status-bar {
  background-color: #1e1f29;
  border-color: #44475a;
}

.dracula .toolbar button {
  background-color: #282a36;
  border-color: #44475a;
  color: #f8f8f2;
}

.dracula .toolbar button:hover {
  background-color: #44475a;
}

.dracula .outline-panel {
  background-color: #1e1f29;
  border-color: #44475a;
}

.dracula .outline-item {
  color: #f8f8f2;
}

.dracula .outline-item:hover {
  background-color: #44475a;
}

.dracula .outline-item.active {
  background-color: #bd93f9;
  color: #282a36;
}

/* 为所有主题添加代码块样式 */
:deep(pre) {
  margin: 1em 0;
  padding: 1em;
  border-radius: 6px;
  overflow-x: auto;
}

/* GitHub 主题代码块 */
.github :deep(pre) {
  background-color: #f6f8fa;
  border: 1px solid #e1e4e8;
}

/* Monokai 主题代码块 */
.monokai :deep(pre) {
  background-color: #3e3d32;
  border: 1px solid #49483e;
}

/* Solarized 主题代码块 */
.solarized :deep(pre) {
  background-color: #eee8d5;
  border: 1px solid #ddd6c1;
}

/* Dracula 主题代码块 */
.dracula :deep(pre) {
  background-color: #44475a;
  border: 1px solid #6272a4;
}

/* 链接样式 */
.github :deep(a) { color: #0366d6; }
.monokai :deep(a) { color: #a6e22e; }
.solarized :deep(a) { color: #268bd2; }
.dracula :deep(a) { color: #8be9fd; }

/* 标题样式 */
.github :deep(h1), .github :deep(h2) {
  border-bottom-color: #eaecef;
}

.monokai :deep(h1), .monokai :deep(h2) {
  border-bottom-color: #3e3d32;
}

.solarized :deep(h1), .solarized :deep(h2) {
  border-bottom-color: #eee8d5;
}

.dracula :deep(h1), .dracula :deep(h2) {
  border-bottom-color: #44475a;
}

/* 引用样式 */
.github :deep(blockquote) {
  border-left-color: #dfe2e5;
  background-color: #f6f8fa;
}

.monokai :deep(blockquote) {
  border-left-color: #a6e22e;
  background-color: #3e3d32;
}

.solarized :deep(blockquote) {
  border-left-color: #268bd2;
  background-color: #eee8d5;
}

.dracula :deep(blockquote) {
  border-left-color: #bd93f9;
  background-color: #44475a;
}

/* 表格样式 */
.github :deep(table) { border-color: #e1e4e8; }
.monokai :deep(table) { border-color: #3e3d32; }
.solarized :deep(table) { border-color: #eee8d5; }
.dracula :deep(table) { border-color: #44475a; }

/* 表格头部样式 */
.github :deep(th) { background-color: #f6f8fa; }
.monokai :deep(th) { background-color: #3e3d32; }
.solarized :deep(th) { background-color: #eee8d5; }
.dracula :deep(th) { background-color: #44475a; }

/* 表格交替行样式 */
.github :deep(tr:nth-child(even)) { background-color: #f6f8fa; }
.monokai :deep(tr:nth-child(even)) { background-color: #35352d; }
.solarized :deep(tr:nth-child(even)) { background-color: #eee8d5; }
.dracula :deep(tr:nth-child(even)) { background-color: #313341; }

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  min-width: 160px;
  padding: 8px 0;
  margin: 4px 0 0;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.dropdown-item {
  display: block;
  width: 100%;
  padding: 8px 16px;
  clear: both;
  font-weight: 400;
  color: #333;
  text-align: inherit;
  white-space: nowrap;
  background-color: transparent;
  border: 0;
  cursor: pointer;
}

.dropdown-item:hover {
  background-color: #f5f5f5;
  color: #4CAF50;
}

.dropdown-divider {
  height: 0;
  margin: 8px 0;
  overflow: hidden;
  border-top: 1px solid #ddd;
}

.ws-status {
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  background-color: #f5f5f5;
  color: #666;
  margin-left: 8px;
  display: inline-block;
}

.ws-status.connected {
  background-color: #e6f4ea;
  color: #1e8e3e;
}

.ws-status.error {
  background-color: #fce8e6;
  color: #d93025;
}
</style> 